/**
 ******************************************************************************
 * @file    exatron.c
 * @author  exatron
 * @version V1.0.0
 * @date    segunda, 22 de dezembro de 2014
 * @brief   Command interpreter.
 ******************************************************************************
 * @attention
 *
 *
 ******************************************************************************
 */

/**
  * @addtogroup Common
  * @{
  */

/* Includes ------------------------------------------------------------------*/
#include "common.h"

/* Variáveis dos sockets */
Socket_t        sock[N_SOCKS];	  	/*!< Estrutura de sockets */
FIFO_t          isrx_fifo;			/*!< FIFO da fila de sockets
									     com dados no Rx */
char            isrx_id[N_SOCKS];   /*!< Buffer que guarda os ID's
									     dos sockets com dados no
										 Rx */
extern Select_t Select;

/* Private function prototypes -----------------------------------------------*/
void main_handler(void);
void main_init(void);

/* Private functions ---------------------------------------------------------*/

/**
  * @defgroup Common_Functions
  * @{
  */

/**
  * @brief  Processo responsável por interpretar os comandos recebidos pela
  * 		   serial.
  * @param  Nenhum
  * @retval Nenhum
  */
int main(void)
{
	int ret_sel = 0;
	main_init();

	while(1)
	{
		/* Operações sobre select global */
		Select_Clear();
		Select_Set();
		Select_Maxfd();

        // Espera acontecimento em algum fd
		do
		{
			usleep(SYS_DELAY);
			ret_sel = select(Select.max_fd, &Select.readfds, NULL, NULL, NULL);
		}while(ret_sel == -1);

        Select_Exec();
	}

	return EXIT_SUCCESS;
}

void Select_Exec(void)
{
	int i = 0;

	/* Verifica clients TCP's */
	for(i=Sock0;i<(N_BACKLOG+Sock0);i++)
	{
		if(Select_IsSet(i + 1) > 0)
		{
			TCP_OpenServer_recv(i);
			usleep(SYS_DELAY);
		}
	}

	/* Verifica TCP Server */
	if(Select_IsSet(Select_TCPServerSocket) > 0)
	{
		TCP_OpenServer_accept(TCP_ServerSocketID);
		usleep(SYS_DELAY);
	}

	/* Verifica UDP Server */
	if(Select_IsSet(Select_UDPServerSocket) > 0)
	{
		UDP_OpenServer_recv(UDP_ServerSocketID);
		usleep(SYS_DELAY);
	}

	/* Verifica TCP Client */
	if(Select_IsSet(Select_TCPClientSocket) > 0)
	{
		TCP_ConnClient_recv(TCP_ClientSocketID);
		usleep(SYS_DELAY);
	}

	/* Verifica UDP Client */
	if(Select_IsSet(Select_UDPClientSocket) > 0)
	{
		UDP_OpenClient_recv(UDP_ClientSocketID);
		usleep(SYS_DELAY);
	}

	/* Verifica serial de comando */
	if(Select_IsSet(Select_usart0) > 0)
	{
		main_handler();
	}
}

void main_init(void)
{
	char cmd[255];

	/* Seta prioridade máxima */
	setpriority(PRIO_PROCESS, getpid(), -20);

	/* Ignora sinal SIGTERM */
	signal(SIGTERM, SIG_IGN);

	/* Espera sistema ficar estável */
	sleep(20);

	/* Desabilita OOM Killer */
	bzero(cmd, sizeof(cmd));
	sprintf(cmd, "echo -17 > /proc/%d/oom_adj", getpid());
	system(cmd);

	/* Inicialização */
	aux_mkdir();
	aux_ClearFlags();
	aux_USART_open();

	/* Escreve a sequência de inicialização */
	aux_USART0_puts("START\r\n");
	if(aux_GetConnectionState() == Status_SoftAP)
		aux_USART0_puts("AP;%s\r\n", aux_FileRdLine(PATH_CONF, "ssid", "Erro lendo ssid\r\n"));
	else
		aux_USART0_puts("STA;%s\r\n", aux_FileRdLine(PATH_CONF, "ssid", "Erro lendo ssid\r\n"));

	/* Verificação de timeout socket e estado de conexão */
	signal(SIGALRM, aux_back_functions);
	alarm(1);
}

void main_handler(void)
{
	char command[USART_RX_LEN]; 		/*!< Recebe o comando da serial */
	char args[10][USART_RX_LEN];		/*!< Vetor de argumentos */
	char *pch;							/*!< Ponteiro para divisão arg */
	int nbytes = 0;						/*!< Numero de bytes recebidos no get da serial */
	int nargs = 1;						/*!< Numero de argumentos */
	int opcao = 0;						/*!< Numero da opcao */

	/* Get da serial */
	bzero(command, sizeof(command));
	bzero(args, sizeof(args));
	nbytes = aux_USART0_gets(command);

	/* Se Recebeu algo válido */
	if(nbytes > 0)
	{
		usleep(SYS_DELAY*10);

		/* Se o comando for um = */
		if(strcmp(command, "=") == 0 || nbytes == 0)
			sprintf(command, "%d", Result_Error);

		/* Pega o comando */
		pch = strtok(command, "=");

		if(pch == NULL) return;

		strcpy(args[0], pch);
		nargs = 1;

		/* Se entrada numérica */
		if(strlen(args[0]) < 3)
			if(aux_IsNumber(args[0]) == TRUE)
				opcao = atoi(args[0]);
			else
				opcao = Result_Error;
		/* Se entrada por acrônimo */
		else
			opcao = aux_gettaskid(args[0]);

		/* Seta como ocupado */
		aux_SetBusy(TRUE);

		/* Separa parâmetros */
		while(pch != NULL && nargs < 10)
		{
			pch = strtok(NULL, ";");
			if(pch != NULL)
			{
				strcpy(args[nargs], pch);
				nargs++;
			}
		}

		switch(opcao)
		{
			case WF_GRM:
				WF_GetRadioMAC();
				break;
			case WF_GIP:
				WF_GetIP();
				break;
			case WF_GRIP:
				WF_GetRouterIP();
				break;
			case WF_CSAP:
				if(nargs == 4)
				{
					WF_ConnectSofAP(args[1], args[2], args[3]);
				}
				else if(nargs == 2)
				{
					WF_ConnectSofAP(args[1], "12345678", "none");
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "WF_CSAP", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case WF_CIK:
				if(nargs == 4)
				{
					WF_ConnectInfraKey(args[1], args[2], args[3]);
				}
				else if(nargs == 2)
				{
					WF_ConnectInfraKey(args[1], "12345678", "none");
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "WF_CIK", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case WF_CST:
				WF_ConnectionState();
				break;
			case WF_DCN:
				WF_Disconnect();
				break;
			case WF_SCAN:
				/* Verifica consistência RSSI */
				if(aux_IsNumber(args[1]) != TRUE)
				{
					if(args[1][0] == '-')
					{
						if(aux_IsNumber(args[1]+1) != TRUE)
							nargs = 0;
					}
					else
						nargs = 0;
				}

				if(nargs == 2)
				{
					WF_Scan(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "WF_SCAN", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case WF_ISD:
				WF_IsScanDone();
				break;
			case WF_SRT:
				WF_ScanResult();
				break;
			case WF_PIP:
				if(nargs == 2)
				{
					WF_PingIP(args[1]);
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "WF_PIP", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case WF_IPOK:
				WF_IsPingOK();
				break;
			case SCK_IRDR:
				if(SCK_CheckID(args[1]) == TRUE)
				{
					SCK_IsRxDataReady(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SCK_IRDR", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SCK_IRDR2:
				SCK_IsRxDataReady2();
				break;
			case SCK_RXD:
				if(SCK_CheckID(args[1]) == TRUE)
				{
					SCK_RxData(atoi(args[1]));
				}
				else
				{
					aux_USART1_puts("%s=%d\r\n", "SCK_RXD", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SCK_ITDR:
				if(SCK_CheckID(args[1]) == TRUE)
				{
					SCK_IsTxDataReady(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SCK_ITDR", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SCK_TXD:
				/* Verifica consistência do ID */
				if(SCK_CheckID(args[1]) == FALSE)
					nargs = 0;
				/* Verifica consistência do tamanho */
				else if(aux_IsNumber(args[2]) == FALSE)
					nargs = 0;
				else if(atoi(args[2]) > USART_RX_LEN)
					sprintf(args[2], "%d", USART_RX_LEN);
				else if(atoi(args[2]) < 1)
					nargs = 0;

				if(nargs == 3)
				{
					SCK_TxData(atoi(args[1]), atoi(args[2]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SCK_TXD", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SCK_GSS:
				/* Verifica consistência do id */
				if(SCK_CheckID(args[1]) == TRUE)
				{
					SCK_GetStatusSocket(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SCK_GSS", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SCK_CLOS:
				/* Verifica consistência do id */
				if(SCK_CheckID(args[1]) == TRUE)
				{
					SCK_Close(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SCK_CLOS", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case TCP_CNC:
				/* Verifica consistência da porta */
				if(aux_IsNumber(args[2]) != TRUE)
					nargs = 0;

				if(nargs == 3)
				{
					TCP_ConnClient(TCP_ClientSocketID, args[1],atoi(args[2]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "TCP_CNC", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case TCP_OPS:
				/* Verifica consistência da porta */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					TCP_OpenServer(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "TCP_OPS", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case UDP_OPC:
				/* Verifica consistência da porta */
				if(aux_IsNumber(args[2]) != TRUE)
					nargs = 0;

				if(nargs == 3)
				{
					UDP_OpenClient(UDP_ClientSocketID, args[1],atoi(args[2]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "UDP_OPC", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case UDP_OPS:
				/* Verifica consistência da porta */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					UDP_OpenServer(UDP_ServerSocketID, atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "UDP_OPS", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case CFG_SNP:
				/* Verifica NetworkType_t */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(atoi(args[1]) == DHCP_NETWORK && nargs == 2)
				{
					CFG_SetNetworkParameters(atoi(args[1]), "", "", "");
				}
				else if(nargs == 4)
				{
					CFG_SetNetworkParameters(STATIC_NETWOTK, args[2], args[3], args[2]);
				}
				else if(nargs == 5)
				{
					CFG_SetNetworkParameters(STATIC_NETWOTK, args[2], args[3], args[4]);
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "CFG_SNP", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case CFG_GNP:
				CFG_GetNetworkParameters();
				break;
			case CFG_STOS:
				/* Verifica consistência do timeout */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					CFG_SetTimeOutSocket(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "CFG_STOS", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case CFG_GTOS:
				CFG_GetTimeOutSocket();
				break;
			case CFG_STOU:
				/* Verifica consistência do timeout */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					CFG_SetTimeOutUSART(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "CFG_STOU", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case CFG_GTOU:
				CFG_GetTimeOutUSART();
				break;
			case CFG_SBR:
				/* Verifica consistência da serial */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;
				else if(atoi(args[1]) > 1 || atoi(args[1]) < 0)
					nargs = 0;
				/* Verifica consistência do baudrate */
				if(aux_IsNumber(args[2]) != TRUE)
					nargs = 0;

				if(nargs == 3)
				{
					CFG_SetBaudRate(atoi(args[1]), atoi(args[2]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "CFG_SBR", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case CFG_GBR:
				/* Verifica consistência da serial */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;
				else if(atoi(args[1]) > 1 || atoi(args[1]) < 0)
					nargs = 0;

				if(nargs == 2)
				{
					CFG_GetBaudRate(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "CFG_GBR", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SW_R:
				SW_Reboot();
				break;
			case SW_GV:
				SW_GetVersion();
				break;
			case SW_CB:
				SW_ClearBusy();
				break;
			case SW_EXEC:
				if(nargs == 2)
				{
					SW_Execute(args[1]);
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SW_EXEC", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SW_CSC:
				/* Verifica consistência da opção */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					SW_ConnStatusConf(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SW_CSC", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			case SW_RGC:
				/* Verifica consistência da opção */
				if(aux_IsNumber(args[1]) != TRUE)
					nargs = 0;

				if(nargs == 2)
				{
					SW_RingConf(atoi(args[1]));
				}
				else
				{
					aux_USART0_puts("%s=%d\r\n", "SW_RGC", Result_BadArgument);
					aux_SetBusy(FALSE);
				}
				break;
			default:
				aux_USART0_puts("%s=%d\r\n", "ERROR", Result_BadArgument);
				aux_SetBusy(FALSE);
				break;
		}
	}
}

/**
 * @}
 */

/**
 * @}
 */
